package com.ldr.custom.spring.v3.context;

import com.ldr.custom.spring.v3.beans.GPBeanDefinition;
import com.ldr.custom.spring.v3.beans.GPBeanWrapper;
import com.ldr.custom.spring.v3.beans.GPDefaultListableBeanFactory;
import com.ldr.custom.spring.v3.context.support.GPBeanDefinitionReader;
import com.ldr.custom.spring.v3.core.GPBeanFactory;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * IOC容器
 * v2版本只是涉及IOC
 */
public class GPApplicationContext extends GPDefaultListableBeanFactory implements GPBeanFactory {


    private String[] configLocations;
    private GPBeanDefinitionReader reader;


    //用来存储所有的被代理过的对象
    private Map<String, GPBeanWrapper> beanWrapperMap = new ConcurrentHashMap<>();

    public GPApplicationContext(String... locations) {
        this.configLocations = locations;
        refresh();
    }

    public void refresh() {
        //定位
        this.reader = new GPBeanDefinitionReader(this.configLocations);
        //加载
        List<String> beanDefinitions = this.reader.loadBeanDefinitions();
        //注册
        doRegister(beanDefinitions);
        //依赖注入（自动注入，lazy-init=false），自动调用getBean方法
        doAutowried();
    }

    //开始执行依赖注入
    private void doAutowried() {
        for (Map.Entry<String, GPBeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {
            String beanName = beanDefinitionEntry.getKey();
            if (!beanDefinitionEntry.getValue().isLazyInit()) {
                //获取Bean实例
                getBean(beanName);
            }
        }


//        for (Map.Entry<String, GPBeanWrapper> wrapperEntry : this.beanWrapperMap.entrySet()) {
//
//            //类上有@Autowried注解，进行依赖注入方法
//            populateBean(wrapperEntry.getKey(), wrapperEntry.getValue().getOriginalInstance());
//        }
    }

//    public void populateBean(String beanName, Object instance) {
//        Class<?> clazz = instance.getClass();
//        if (!clazz.isAnnotationPresent(GPController.class)
//                && !clazz.isAnnotationPresent(GPService.class)) {
//            return;
//        }
//
//        Field[] fields = clazz.getDeclaredFields();
//        for (Field field : fields) {
//            if (!field.isAnnotationPresent(GPAutowried.class)) continue;
//
//            GPAutowried autowried = field.getAnnotation(GPAutowried.class);
//            String autowriedName = autowried.value().trim();
//            if ("".equals(autowriedName)) {
//                autowriedName = field.getType().getName();
//            }
//
//            field.setAccessible(true);
//
//            try {
//
//                //把aop代理对象依赖注入进去
//                field.set(instance, this.beanWrapperMap.get(autowriedName).getWrapperInstance());
//            } catch (IllegalAccessException e) {
//                e.printStackTrace();
//            }
//
//        }
//    }

    //真正的将BeanDefinition注册到BeanDefinitionMap
    private void doRegister(List<String> beanDefinitions) {
        //beanName三种情况：
        //1 默认是类名首字母小写
        //2 自定义名称
        //3 接口注入

        try {
            for (String className : beanDefinitions) {

                Class<?> beanClass = Class.forName(className);

                //如果是一个接口，是不能实例化的
                //用它的实现类来实例化
                if (beanClass.isInterface()) continue;


                GPBeanDefinition beanDefinition = reader.registerBean(className);
                if (beanDefinition != null) {
                    beanDefinitionMap.put(beanDefinition.getFactoryBeanName(), beanDefinition);
                }


                Class<?>[] interfaces = beanClass.getInterfaces();
                for (Class<?> i : interfaces) {
                    //如果是多个实现类，只能覆盖
                    //spring没那么智能
                    //这个时候，可以自定义名字
                    this.beanDefinitionMap.put(i.getName(), beanDefinition);
                }


                //到这里为止，容器初始化完毕
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


    }


    /**
     * 通过读取BeanDefinition中的信息
     * 然后通过反射机制创建一个实例并返回
     * Spring做法是，不会把最原始对象放出去，会用一个BeanWrapper来进行一次包装
     * 装饰器模式：1、保留原来的OOP关系 2、需要对它进行扩展，增强（为以后AOP打基础）
     */
    @Override
    public Object getBean(String beanName) {

        GPBeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        if (beanDefinition == null) {
            return null;
        }

        setAopConfig(reader.getConfig());
        //调用BeanFactory创建实例
        return doCreateBean(beanName, beanDefinition, null);


//        try {
//
//            //生成通知事件
//            GPBeanPostProcessor postProcessor = new GPBeanPostProcessor();
//
//
//            Object instance = instanceBean(beanDefinition);
//
//            if (instance == null) return null;
//            //在实例初始化以前调用一次
//            postProcessor.postProcessBeforeInitialization(instance, beanName);
//
//            GPBeanWrapper beanWrapper = new GPBeanWrapper(instance);
//
//
//            //设置aop配置
//            beanWrapper.setAopConfig(instanceAopConfig(beanDefinition));
//
//            beanWrapper.setPostProcessor(postProcessor);
//
//            this.beanWrapperMap.put(beanName, beanWrapper);
//
//            //在实例初始化以后调用一次
//            postProcessor.postProcessAfterInitialization(instance, beanName);
//
//
//            // populateBean(beanName,instance);
//
//            //通过这样一调用，相当于给我们自己留有了可操作的空间
//            //把aop的动态代理对象返回出去
//            return this.beanWrapperMap.get(beanName).getWrapperInstance();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

    }


//    private GPAopConfig instanceAopConfig(GPBeanDefinition beanDefinition) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException {
//
//        GPAopConfig config = new GPAopConfig();
//        String expression = reader.getConfig().getProperty("pointCut");
//        String[] before = reader.getConfig().getProperty("aspectBefore").split("\\s");
//        String[] after = reader.getConfig().getProperty("aspectAfter").split("\\s");
//
//
//        String className = beanDefinition.getBeanClassName();
//
//        Class<?> clazz = Class.forName(className);
//
//        Pattern pattern = Pattern.compile(expression);
//
//        Class<?> aspectClass = Class.forName(before[0]);
//
//        for (Method method : clazz.getMethods()) {
//            //public .* com\.ldr\.custom\.spring\.demo\.service\..*Service\..*\(.*\)
//            //public java.lang.String com.ldr.custom.spring.demo.service.impl.queryById(java.lang.Integer)
//            Matcher matcher = pattern.matcher(method.toString());
//
//            if (matcher.matches()) {
//                //能满足切面规则的类，添加Aop配置中
//                config.put(method, aspectClass.newInstance(), new Method[]{aspectClass.getMethod(before[1]), aspectClass.getMethod(after[1])});
//            }
//        }
//
//
//        return config;
//    }


    public String[] getBeanDefinitionNames() {


        return this.beanDefinitionMap.keySet().toArray(new String[this.beanDefinitionMap.size()]);
    }

    public int getBeanDefinitionCount() {
        return this.beanDefinitionMap.size();
    }


    public Properties getConfig() {
        return this.reader.getConfig();
    }


}
